package com.zf.thread_pool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.concurrent.*;

/**
 * 线程池管理器
 */
public class ExecutorManager {
    private static final Logger log = LoggerFactory.getLogger(ExecutorManager.class);


    /**
     * 关闭JVM时，优雅的关闭指定的线程池
     */
    public static void shutdownThreadPoolWhenShutdownJvm(ExecutorService executor) {
        if (Objects.isNull(executor)) {
            return;
        }
        Runtime.getRuntime().addShutdownHook(new Thread(executor::shutdown));
    }


    /**
     * 定时打印线程池的信息
     *
     * @param executor        线程池
     * @param threadPoolName  线程池的名称
     * @param fixedRatePeriod 间隔周期
     * @param unit            间隔周期的单位
     */
    public static void printPoolStatusAtFixedRate(ThreadPoolExecutor executor, String threadPoolName, long fixedRatePeriod, TimeUnit unit) {
        // 配置一个定时器，定时 每隔 1s 输出一次 commonPool 线程池的状态信息
        ScheduledExecutorService scheduledPrintExecutor = Executors.newSingleThreadScheduledExecutor();
        scheduledPrintExecutor.scheduleAtFixedRate(() -> {
            String message = ">>[线程池<{}>状态]: [shutdown={}, Terminated={}], " +
                    "当前线程数量: {}, 曾经最大线程数量: {}, " +
                    "当前活跃线程数量: {}, 接收的任务总数量: {}, 已完成的任务数量: {}, " +
                    "当前队列中任务数量: {}, 当前队列剩余容量: {}";
            boolean isShutdown = executor.isShutdown(); // 线程池否被关闭，不能再接收新的任务，已有的任务继续执行
            boolean isTerminated = executor.isTerminated(); // 线程池是否终止，所有任务都已完成，线程都被终止
            int poolSize = executor.getPoolSize(); // 此刻 线程池中存在的所有线程的数量，包括 活跃的、阻塞的、空闲的
            int largestPoolSize = executor.getLargestPoolSize(); // 所有时刻中，线程池中曾经同时存在的最大线程数量
            int activeCount = executor.getActiveCount(); // 此刻 线程池中 活跃(运行中的、阻塞的都算是活跃的)的线程数量；近似值，因为线程在不断的处理任务，所以状态时刻都在变化
            long totalTaskCount = executor.getTaskCount(); // 此刻 线程池中 所有的任务的数量，包括“已经完成的、正在运行的、工作队列中”的任务数量；近似值，因为线程在不断的处理任务，所以状态时刻都在变化
            long completedTaskCount = executor.getCompletedTaskCount(); // 到目前为止，已经完成的任务数量；近似值，因为线程在不断的处理任务，所以状态时刻都在变化
            int queueSize = executor.getQueue().size();  // 此刻 工作队列中的任务数量
            int queueRemainingCapacity = executor.getQueue().remainingCapacity(); // 此刻 工作队列的剩余容量

            Object[] params = new Object[]{
                    threadPoolName, isShutdown, isTerminated,
                    poolSize, largestPoolSize,
                    activeCount, totalTaskCount, completedTaskCount,
                    queueSize, queueRemainingCapacity
            };

            // 当工作队列的剩余容量小于某个值时，打印警告日志
            if (queueRemainingCapacity <= 32) {
                log.warn(message, params);
            } else {
                log.info(message, params);
            }

            // 如果 executor 线程池终结了，则关闭定时输出
            if (executor.isTerminated()) {
                scheduledPrintExecutor.shutdown();
            }

        }, 10, fixedRatePeriod, unit);

        // 给JVM进程添加关闭时的回调，当JVM进程关闭时 优雅的关闭线程池
        Runtime.getRuntime().addShutdownHook(new Thread(scheduledPrintExecutor::shutdown));
    }
}
